home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
aminet
/
comm
/
misc
/
xqsrc931030.lzh
/
library
/
session.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-29
|
13KB
|
533 lines
/*
* Name: session.c
*
* Description: Session management functions for xferq.library
*
* Copyright: 1992-1993 by David Jones.
*
* Distribution:
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to:
*
* The Free Software Foundation David Jones
* 675 Mass Ave 6730 Tooney Drive
* Cambridge, MA Orleans, Ontario
* 02139 K1C 6R4
* USA Canada
*
* Usenet: gnu@prep.ai.mit.edu dej@qpoint.ocunix.on.ca
* Fidonet: 1:163/109.8
*
* $Log: $
*
*/
#include <exec/types.h>
#include "xferq.h"
#include "xferqint.h"
#include "xferq_pragmas.h"
#include <proto/exec.h>
#include <utility/tagitem.h>
#include <proto/utility.h>
#include <exec/lists.h>
#include "execlists.h"
#include <exec/semaphores.h>
extern struct SignalSemaphore QueueLock;
extern struct MinList QueueList;
void PostCreateSession(struct Session *session)
/*
* In: session Pointer to session to initialize
*
* Does: Initializes a session structure once created. This involves
* setting up the site list.
*/
{
NEWLIST(&session->sessList);
}
void PreDropSession(struct Session *session)
/*
* In: session Pointer to session to drop
*
* Does: Ends all sessions on the given cookie.
*/
{
XfqEndSession(session, NULL);
}
ULONG __saveds __asm LIBSessionUp(register __a0 struct NetAddress *addr)
/*
* In: addr A0 Address to test existence of session on
*
* Does: Returns TRUE if there's a session active to the given address.
* Returns FALSE otherwise.
*/
{
struct SiteNode *sn;
BOOL result;
ObtainSemaphore(&QueueLock);
sn = FindSiteQueue(addr);
if (sn) {
result = sn->numSessions != 0;
}
else {
result = FALSE;
}
ReleaseSemaphore(&QueueLock);
return result;
}
struct SessNode *FindSessNode(struct Session *session,
struct NetAddress *addr)
/*
* In: session Session cookie to scan
* addr Address to search for
*
* Does: Searches for the address in the session cookie and returns
* a pointer to the session node if found and NULL otherwise.
*/
{
struct SessNode *sn;
sn = FIRST(&session->sessList);
while (NEXT(sn)) {
if (!XfqCmpAddressTags(addr, sn->addr,
XQ_Mandatory, XQADDR_ALLBUTUSER,
TAG_DONE)) {
return sn;
}
sn = NEXT(sn);
}
return NULL;
}
void AddSessNodeSorted(struct Session *session, struct SessNode *node,
struct SessNode *last)
/*
* In: session Session to add node to
* node Pointer to node to add
* last Pointer to last node added
*
* Does: Adds the node to the session in sorted order. The last node
* is given for performance purposes.
*/
{
struct MinList *list;
struct SessNode *probe;
list = &session->sessList;
probe = FIRST(list);
if (!NEXT(probe)) {
ADDHEAD(list, node);
return;
}
if (XfqCmpAddress(node->addr, probe->addr, NULL) < 0) {
ADDHEAD(list, node);
return;
}
probe = LAST(list);
if (XfqCmpAddress(node->addr, probe->addr, NULL) < 0) {
ADDTAIL(list, node);
return;
}
if (XfqCmpAddress(node->addr, last->addr, NULL) > 0) {
probe = NEXT(last);
while (XfqCmpAddress(node->addr, probe->addr, NULL) > 0) {
probe = NEXT(probe);
}
INSERT(list, node, PREV(probe));
return;
}
else {
probe = PREV(last);
while (XfqCmpAddress(node->addr, probe->addr, NULL) < 0) {
probe = PREV(probe);
}
INSERT(list, node, probe);
}
}
ULONG __saveds __asm LIBBeginSession(register __a0 struct Session *session,
register __a1 struct TagItem *tags)
/*
* In: session A0 Session cookie to add address to
* tags A1 Taglist controlling operation
*
* Does: Starts a session to the given site. If the session is a public
* session, then the fact that you have started a session will be
* visible to all callers. If the session started successfully,
* the function returns TRUE. Otherwise, it returns FALSE.
*
* XQ_AddHead Add the data to the front of the list in the
* session cookie.
* XQ_AddTail Add the data to the tail of the list in the
* session cookie.
* XQ_AddSorted Add each datum in sorted order. This assumes the
* session cookie is already sorted.
*
* In all cases, the data may be either an address or a session.
* If a session, this is equivalent to performing the operation
* will all addresses in the session. More than one occurrence of
* each operation tag is permitted.
*/
{
struct MinList memList;
BOOL public, result;
struct TagItem *tag, *walk;
struct SessNode *sn, *wsn, *tsn, *last;
struct Session *source;
struct SiteNode *sq;
public = !(session->flags & XQSESS_PRIVATE);
/*
* Prepass: ensure enough memory to go around.
*/
NEWLIST(&memList);
result = TRUE;
walk = tags;
while (result && (tag = NextTagItem(&walk))) {
switch (tag->ti_Tag) {
case XQ_AddHead:
case XQ_AddTail:
case XQ_AddSorted:
source = (struct Session *)tag->ti_Data;
if (ObjectType(source) == XQO_ADDRESS) {
sn = AllocMemory(sizeof(struct SessNode));
if (sn) {
ADDHEAD(&memList, sn);
}
else {
result = FALSE;
}
}
else {
wsn = FIRST(&source->sessList);
while (result && (tsn = NEXT(wsn))) {
sn = AllocMemory(sizeof(struct SessNode));
if (sn) {
ADDHEAD(&memList, sn);
}
else {
result = FALSE;
}
wsn = tsn;
}
}
break;
}
}
if (!result) {
sn = FIRST(&memList);
while (tsn = NEXT(sn)) {
FreeMemory(sn);
sn = tsn;
}
SetErrorTags(tags);
return FALSE;
}
if (public) {
ObtainSemaphore(&QueueLock);
}
walk = tags;
last = NULL;
while (tag = NextTagItem(&walk)) {
switch (tag->ti_Tag) {
case XQ_AddHead:
if (ObjectType(tag->ti_Data) == XQO_ADDRESS) {
sn = REMHEAD(&memList);
sn->addr = (struct NetAddress *)tag->ti_Data;
XfqCopyObject(sn->addr);
ADDHEAD(&session->sessList, sn);
if (public) {
sq = FindSiteQueue(sn->addr);
sq->numSessions++;
}
last = sn;
}
else {
source = (struct Session *)tag->ti_Data;
wsn = LAST(&source->sessList);
while (tsn = PREV(wsn)) {
sn = REMHEAD(&memList);
sn->addr = wsn->addr;
XfqCopyObject(sn->addr);
ADDHEAD(&session->sessList, sn);
if (public) {
sq = FindSiteQueue(sn->addr);
sq->numSessions++;
}
wsn = tsn;
}
last = sn;
}
break;
case XQ_AddTail:
if (ObjectType(tag->ti_Data) == XQO_ADDRESS) {
sn = REMHEAD(&memList);
sn->addr = (struct NetAddress *)tag->ti_Data;
XfqCopyObject(sn->addr);
ADDTAIL(&session->sessList, sn);
if (public) {
sq = FindSiteQueue(sn->addr);
sq->numSessions++;
}
last = sn;
}
else {
source = (struct Session *)tag->ti_Data;
wsn = FIRST(&source->sessList);
while (tsn = NEXT(wsn)) {
sn = REMHEAD(&memList);
sn->addr = wsn->addr;
XfqCopyObject(sn->addr);
ADDTAIL(&session->sessList, sn);
if (public) {
sq = FindSiteQueue(sn->addr);
sq->numSessions++;
}
wsn = tsn;
}
last = sn;
}
break;
case XQ_AddSorted:
if (ObjectType(tag->ti_Data) == XQO_ADDRESS) {
sn = REMHEAD(&memList);
sn->addr = (struct NetAddress *)tag->ti_Data;
XfqCopyObject(sn->addr);
AddSessNodeSorted(session, sn, last);
if (public) {
sq = FindSiteQueue(sn->addr);
sq->numSessions++;
}
last = sn;
}
else {
source = (struct Session *)tag->ti_Data;
wsn = LAST(&source->sessList);
while (tsn = PREV(wsn)) {
sn = REMHEAD(&memList);
sn->addr = wsn->addr;
XfqCopyObject(sn->addr);
AddSessNodeSorted(session, sn, last);
if (public) {
sq = FindSiteQueue(sn->addr);
sq->numSessions++;
}
last = sn;
wsn = tsn;
}
}
break;
}
}
if (public) {
ReleaseSemaphore(&QueueLock);
}
SetErrorTags(tags);
return TRUE;
}
void __saveds __asm LIBEndSession(register __a0 struct Session *session,
register __a1 void *object)
/*
* In: session A0 Session cookie to end session to
* object A1 Address/session to end session to
*
* Does: Removes the address from the given session. If the session is
* a public session, then the address is removed globally and the
* queue in question is scanned:
*
* XQ_IMMEDIATE nodes are marked as cancelled.
* XQ_SENDLATER nodes have the SENDLATER flag cleared.
*
* The object may be a site or a session. If a session, then
* all sites on that session will be removed from the first session.
* The object may also be NULL, in which case all objects are
* removed from the session.
*/
{
struct SessNode *sn, *wsn, *tsn;
struct SiteNode *sq;
struct Session *source;
BOOL public;
if (!object) {
object = session;
}
public = !(session->flags & XQSESS_PRIVATE);
if (public) {
ObtainSemaphore(&QueueLock);
}
if (ObjectType(object) == XQO_ADDRESS) {
sn = FindSessNode(session, object);
if (sn) {
REMOVE(sn);
if (public) {
sq = FindSiteQueue(object);
if (!--sq->numSessions) {
SessionDownQueue(sq);
}
}
XfqDropObject(sn->addr);
FreeMemory(sn);
}
}
else {
source = object;
wsn = FIRST(&source->sessList);
while (tsn = NEXT(wsn)) {
sn = FindSessNode(session, wsn->addr);
if (sn) {
REMOVE(sn);
if (public) {
sq = FindSiteQueue(wsn->addr);
if (!--sq->numSessions) {
SessionDownQueue(sq);
}
}
XfqDropObject(sn->addr);
FreeMemory(sn);
}
wsn = tsn;
}
}
if (public) {
ReleaseSemaphore(&QueueLock);
}
}
void __saveds __asm LIBSortSession(register __a0 struct Session *session,
register __a1 struct TagItem *tags)
/*
* In: session A0 Session cookie to sort
* tags A1 Taglist controlling operation
*
* Does: Puts all of the addresses in the session in sorted order.
* No tags are currently defined.
*/
{
struct MinList tempList;
struct SessNode *sn, *last;
tempList = session->sessList;
NEWLIST(&session->sessList);
last = NULL;
while (sn = REMHEAD(&tempList)) {
AddSessNodeSorted(session, sn, last);
last = sn;
}
SetErrorTags(tags);
}
void __saveds __asm LIBWalkSessionCallBack(
register __a0 struct Session *session,
register __a1 struct TagItem *tags,
register __a4 void *globals)
/*
* In: object A0 Address/session cookie to walk
* tags A1 User/system tags
* globals A4 Pointer to caller's global vector
*
* Does: Walks the session cookie, calling a user-supplied function
* for each address. The user function is given as a standard
* hook structure and is called as follows:
*
* continue = func(hook, address, data) where
*
* hook A0 Pointer to hook structure passed in
* address A2 Pointer to current address
* data A1 User data value passed in to this function
*
* It must return TRUE to continue the walk, FALSE otherwise.
*
* Valid tags are:
* XQ_Reverse Set to TRUE to walk in reverse direction
* XQ_CallBack Data is pointer to user callback hook
* XQ_SessOnly Only walk global nodes that have sessions up
*
* If the session to walk is NULL, then the global session list
* is walked.
*/
{
struct Hook *hook;
BOOL reverse, sessOnly;
struct SessNode *sn, *tsn;
struct SiteNode *sq;
hook = (struct Hook *)GetTagData(XQ_CallBack, NULL, tags);
reverse = GetTagData(XQ_Reverse, FALSE, tags);
sessOnly = GetTagData(XQ_SessOnly, TRUE, tags);
if (session) {
if (reverse) {
sn = LAST(&session->sessList);
while (tsn = PREV(sn)) {
if (!CallHookRes(hook, sn->addr, tags, globals)) {
break;
}
sn = tsn;
}
}
else {
sn = FIRST(&session->sessList);
while (tsn = NEXT(sn)) {
if (!CallHookRes(hook, sn->addr, tags, globals)) {
break;
}
sn = tsn;
}
}
}
else {
ObtainSemaphore(&QueueLock);
if (reverse) {
sq = LAST(&QueueList);
while (PREV(sq)) {
if ((!sessOnly || sq->numSessions) &&
(!CallHookRes(hook, sq->site, tags, globals))) {
break;
}
sq = PREV(sq);
}
}
else {
sq = FIRST(&QueueList);
while (NEXT(sq)) {
if ((!sessOnly || sq->numSessions) &&
(!CallHookRes(hook, sq->site, tags, globals))) {
break;
}
sq = NEXT(sq);
}
}
ReleaseSemaphore(&QueueLock);
}
}